;;; *************************************************************************
;;;; FILE IDENTIFICATION
;;;;
;;;; Name:          dao.lisp
;;;; Purpose:       Audioscrobbler/lastfm DAO
;;;; Programmer:    Nicolas Lamirault <nicolas.lamirault@gmail.com>
;;;;
;;;; This file, part of audioscrobbler, is Copyright (c) 2007 by Nicolas Lamirault
;;;;
;;;; cl-audioscrobbler users are granted the rights to distribute and use this software
;;;; as governed by the terms of the MIT License :
;;;; http://www.opensource.org/licenses/mit-license.php
;;;;
;;;; *************************************************************************


(in-package :cl-audioscrobbler)


(defclass user ()
  ((name :accessor user-name
         :initarg :name
         :initform nil)
   (url :accessor user-url
        :initarg :url
        :initform nil))
  (:documentation "An user."))


(defmethod print-object ((user user) stream)
  (if *print-audioscrobbler*
      (with-slots (name url) user
        (format stream "~&Name: ~A~%Url: ~A~%" name url))
      (print-unreadable-object (user stream :type t :identity t))))


(defclass profile (user)
  ((id :accessor profile-id
       :initarg :id
       :initform nil)
   (registered :accessor profile-registered
               :initarg :registered
               :initform nil)
   (age :accessor profile-age
        :initarg :age
        :initform nil)
   (gender :accessor profile-gender
           :initarg :gender
           :initform nil)
   (country :accessor profile-country
            :initarg :country
            :initform nil))
  (:documentation "Informations about the user."))


(defmethod print-object ((profile profile) stream)
  (if *print-audioscrobbler*
      (with-slots (name url id registered age gender country) profile
        (format stream "~&Name:~A~&Gender:~A~&Age: ~A~&Country: ~A~&Registered: ~A~&Id: ~A~&Url: ~A~%"
                name gender age country registered id url))
      (print-unreadable-object (profile stream :type t :identity t))))


(defclass content ()
 ((name :accessor content-name
        :initarg :name
        :initform nil)
  (mbid :accessor content-mbid
        :initarg :mbid
        :initform nil)
  (url :accessor content-url
       :initarg :url
       :initform nil))
 (:documentation "A music content."))


(defmethod print-object ((content content) stream)
  (if *print-audioscrobbler*
      (with-slots (name mbid url) content
        (format stream "~&~A (~A) : ~A~%" name mbid url))
      (print-unreadable-object (content stream :type t :identity t))))


(defclass top-content (content)
  ((playcount :accessor top-content-playcount
              :initarg :playcount
              :initform nil)
   (rank :accessor top-content-rank
         :initarg :rank
         :initform nil))
  (:documentation "A most played content."))


(defmethod print-object ((top-content top-content) stream)
  (if *print-audioscrobbler*
      (with-slots (name mbid url playcount rank) top-content
        (format stream "~&~A (~A) : ~A [~A] ~A%" name mbid url playcount rank))
      (print-unreadable-object (top-content stream :type t :identity t))))


(defclass artist (content)
  ()
  (:documentation "A music artist."))


(defclass user-top-artist (top-content)
  ()
  (:documentation "A most played music artist."))


(defmethod print-object ((user-top-artist user-top-artist) stream)
  (if *print-audioscrobbler*
      (with-slots (name playcount mbid url rank) user-top-artist
        (format stream "~&Artist: ~A~&Count: ~A~&MBid : ~A~&Url : ~A~&Rank: ~A~%"
                name playcount mbid url rank))
      (print-unreadable-object (user-top-artist stream :type t :identity t))))


(defclass album (content)
 ()
 (:documentation "Album of a music artist."))


(defclass user-top-album (album top-content)
  ((artist-name :accessor user-top-album-artist-name
                :initarg :artist-name
                :initform nil)
   (large :accessor user-top-album-large
          :initarg :large
          :initform nil)
   (medium :accessor user-top-album-medium
           :initarg :medium
           :initform nil)
   (small :accessor user-top-album-small
          :initarg :small
          :initform nil))
  (:documentation "A most played music album."))


(defmethod print-object ((user-top-album user-top-album) stream)
  (if *print-audioscrobbler*
      (with-slots (artist-name playcount large medium small) user-top-album
        (format stream "~&Artist: ~A~&Count: ~A~&Large: ~A~&Medium: ~A~&Small: ~A~%"
                artist-name playcount large medium small))
      (print-unreadable-object (user-top-album stream :type t :identity t))))


(defclass user-top-track (top-content)
 ((artist-name :accessor user-top-track-artist-name
               :initarg :artist-name
               :initform nil))
 (:documentation "A most played music song."))


(defmethod print-object ((user-top-track user-top-track) stream)
  (if *print-audioscrobbler*
      (with-slots (name mbid url playcount rank artist-name) user-top-track
        (format stream "~&Artist: ~A~&Title: ~A~&Count: ~A~&MBid: ~A~&Url: ~A~&Rank: ~A~%"
                artist-name name playcount mbid url rank))
      (print-unreadable-object (user-top-track stream :type t :identity t))))


(defclass neighbour (user)
 ((image :accessor neighbour-image
         :initarg :image
         :initform nil)
  (match :accessor neighbour-match
         :initarg :match
         :initform nil))
 (:documentation "People similar to a profile."))


(defmethod print-object ((neighbour neighbour) stream)
  (if *print-audioscrobbler*
      (with-slots (name url image match) neighbour
        (format stream "~&Name: ~A~%Url: ~A~%Image: ~A~%Match: ~A~%"
                name url image match))
      (print-unreadable-object (neighbour stream :type t :identity t))))


(defclass friend (user)
 ((image :accessor friend-image
         :initarg :image
         :initform nil)
  (connection :accessor friend-connection
              :initarg :connection
              :initform nil))
 (:documentation "Profile's friend."))


(defmethod print-object ((friend friend) stream)
  (if *print-audioscrobbler*
      (with-slots (name url image connection) friend
        (format stream "~&Name: ~A~%Url: ~A~%Image: ~A~%Connection: ~A~%"
                name url image connection))
      (print-unreadable-object (friend stream :type t :identity t))))


(defclass artist-related (artist)
 ((image-small :accessor artist-related-image-small
               :initarg :image-small
               :initform nil)
  (image :accessor artist-related-image
         :initarg :image
         :initform nil))
 (:documentation "A related artist."))


(defmethod print-object ((artist-related artist-related) stream)
  (if *print-audioscrobbler*
      (with-slots (name mbid url image-small image) artist-related
        (format stream "~&Artist: ~A~&Mbid: ~A~&Url: ~A~&Image: ~A~&Small: - ~A%"
                name mbid url image image-small))
      (print-unreadable-object (artist-related stream :type t :identity t))))


(defclass artist-top-album (content)
 ((reach :accessor artist-top-album-reach
         :initarg :reach
         :initform nil))
 (:documentation "A popular artist's album."))


(defmethod print-object ((artist-top-album artist-top-album) stream)
  (if *print-audioscrobbler*
      (with-slots (name mbid url reach) artist-top-album
        (format stream "~&Title: ~A~&Mbid: ~A~&Url: ~A~&Reach: ~A%"
                name mbid url reach))
      (print-unreadable-object (artist-top-album stream :type t :identity t))))


(defclass artist-top-track (content)
 ((reach :accessor artist-top-track-reach
         :initarg :reach
         :initform nil))
 (:documentation "A most played music song for an artist."))


(defmethod print-object ((artist-top-track artist-top-track) stream)
  (if *print-audioscrobbler*
      (with-slots (name mbid url reach) artist-top-track
        (format stream "~&Title:~A~&MBid: ~A~&Url: ~A~&Reach: ~A%"
                name mbid url reach))
      (print-unreadable-object (artist-top-track stream :type t :identity t))))


(defclass fan (user)
 ((image :accessor fan-image
         :initarg :image
         :initform nil)
  (weight :accessor fan-weight
          :initarg :weight
          :initform nil))
 (:documentation "A fan."))


(defmethod print-object ((fan fan) stream)
  (if *print-audioscrobbler*
      (with-slots (name url image weight) fan
        (format stream "~&Name: ~A~%Url: ~A~%Image: ~A~%Weight: ~A~%"
                name url image weight))
      (print-unreadable-object (fan stream :type t :identity t))))


(defclass tag ()
  ((name :accessor tag-name
         :initarg :name
         :initform nil)
   (url :accessor tag-url
        :initarg :url
        :initform nil)
   (count :accessor tag-count
          :initarg :count
          :initform nil))
  (:documentation "A music tag."))


(defmethod print-object ((tag tag) stream)
  (if *print-audioscrobbler*
      (with-slots (name url count) tag
        (format stream "~&Name: ~A~%Url: ~A~%Count: ~A~%"
                name url count))
      (print-unreadable-object (tag stream :type t :identity t))))


(defclass track ()
 ((name :accessor track-name
        :initarg :name
        :initform nil)
  (reach :accessor track-reach
        :initarg :reach
        :initform nil)
  (url :accessor track-url
       :initarg :url
       :initform nil))
 (:documentation "An album track."))


(defmethod print-object ((track track) stream)
  (if *print-audioscrobbler*
      (with-slots (name reach url) track
        (format stream "Name: ~A~%Url: ~A~%Reach: ~A~%"
                name url reach))
      (print-unreadable-object (track stream :type t :identity t))))


(defclass album-infos (user-top-album)
  ((reach :accessor album-reach
          :initarg :reach
          :initform nil)
   (release-date :accessor album-release-date
                 :initarg :release-date
                 :initform nil)
   (tracks :accessor album-info-tracks
           :initarg :tracks
           :initform nil))
  (:documentation "Informations about an album."))


(defmethod print-object ((album-infos album-infos) stream)
  (if *print-audioscrobbler*
      (with-slots (artist-name name release-date large medium small
                               reach tracks) album-infos
        (format stream "Artist: ~A~%Album: ~A~%Release: ~A~&Large: ~A~%Medium: ~A~%Small: ~A~%Reach: ~A~%"
                artist-name name release-date 
                large medium small reach)
        (format stream "Tracks:~%")
        (loop for track in tracks
           do (print-object track stream)))
      (print-unreadable-object (album-infos stream :type t :identity t))))


(defclass recent-track ()
  ((artist :accessor recent-track-artist
           :initarg :artist
           :initform nil)
   (name :accessor recent-track-name
         :initarg :name
         :initform nil)
   (url :accessor recent-track-url
        :initarg :url
        :initform nil)
   (date :accessor recent-track-date
         :initarg :date
         :initform nil))
  (:documentation "A recent track listened by an user."))


(defmethod print-object ((recent-track recent-track) stream)
  (if *print-audioscrobbler*
      (with-slots (artist name url date) recent-track
        (format stream "Artist: ~A~&Name: ~A~&Url: ~A~&Date: ~A~%"
                artist name url date))
      (print-unreadable-object (recent-track stream :type t :identity t))))


(defclass top-artist (artist)
  ((count :accessor top-artist-count
          :initarg :count
          :initform nil)
   (thumbnail :accessor top-artist-thumbnail
              :initarg :thumbnail
              :initform nil)
   (image :accessor top-artist-image
          :initarg :image
          :initform nil))
  (:documentation "An artist tagged the most times with a specified tag."))


(defmethod print-object ((top-artist top-artist) stream)
  (if *print-audioscrobbler*
      (with-slots (name count mbid url thumbnail image) top-artist
        (format stream "Artist: ~A~&Count: ~A~&Mbid: ~A~&Url: ~A~&Thumbnail: ~A~&Image: ~A~%"
                name count mbid url thumbnail image))
      (print-unreadable-object (top-artist stream :type t :identity t))))
             

(defclass top-album (content)
  ((count :accessor top-album-count
          :initarg :count
          :initform nil)
   (large :accessor top-album-large
          :initarg :large
          :initform nil)
   (medium :accessor top-album-medium
           :initarg :medium
           :initform nil)
   (small :accessor top-album-small
          :initarg :small
          :initform nil))
  (:documentation "An album tagged the most times with this tag."))


(defmethod print-object ((top-album top-album) stream)
  (if *print-audioscrobbler*
      (with-slots (name count mbid url large medium small) top-album
        (format stream
                "~&Album: ~A~&Count: ~A~&Mbid: ~A~&Url: ~A~&Large: ~A~&Medium: ~A~&Small: ~A~% "
                name count mbid url large medium small))        
      (print-unreadable-object (top-album stream :type t :identity t))))



(defclass top-track ()
  ((name :accessor top-track-name
         :initarg :name
         :initform nil)
   (url :accessor top-track-url
        :initarg :url
        :initform nil)
   (count :accessor top-track-count
          :initarg :count
          :initform nil)
   (thumbnail :accessor top-track-thumbnail
              :initarg :thumbnail
              :initform nil)
   (image :accessor top-track-image
          :initarg :image
          :initform nil))
  (:documentation "A track tagged the most times with this tag."))


(defmethod print-object ((top-track top-track) stream)
  (if *print-audioscrobbler*
      (with-slots (name url count thumbnail image) top-track
        (format stream "Track: ~A~&Count: ~A~&Url: ~A~&Thumbnail: ~A~&Image: ~A~&"
                name count url thumbnail image))
      (print-unreadable-object (top-track stream :type t :identity t))))


(defclass taste-o-meter ()
  ((score :accessor taste-o-meter-score
          :initarg :score
          :initform nil)
   (first-user :accessor taste-o-meter-first-user
               :initarg :first-user
               :initform nil)
   (second-user :accessor taste-o-meter-second-user
                :initarg :second-user
                :initform nil)
   (artists :accessor taste-o-meter-second-artists
            :initarg :artists
            :initform '()))
  (:documentation "Similarity of this user to another user."))


(defmethod print-object ((taste-o-meter taste-o-meter) stream)
  (if *print-audioscrobbler*
      (with-slots (score first-user second-user artists) taste-o-meter
        (format stream "~&~A - ~A : ~A~&~{~A~^, ~}~%"
                first-user second-user score artists))
      (print-unreadable-object (taste-o-meter stream :type t :identity t))))